home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 4 / Amiga Tools 4.iso / tools / netzwerk / magplip / source / server.c < prev    next >
C/C++ Source or Header  |  1996-02-26  |  34KB  |  1,102 lines

  1. /*
  2. ** $VER: server.c 1.12 (30 Dec 1995)
  3. **
  4. ** magplip.device - Parallel Line Internet Protocol
  5. **
  6. ** Original code written by Oliver Wagner and Michael Balzer.
  7. **
  8. ** This version has been completely reworked by Marius Gröger, introducing
  9. ** slight protocol changes. The new source is a lot better organized and
  10. ** maintainable.
  11. **
  12. ** Additional changes and code cleanup by Jan Kratochvil and Martin Mares.
  13. ** The new source is significantly faster and yet better maintainable.
  14. **
  15. ** (C) Copyright 1993-1994 Oliver Wagner & Michael Balzer
  16. ** (C) Copyright 1995 Jan Kratochvil & Martin Mares
  17. ** (C) Copyright 1995 Marius Gröger
  18. **     All Rights Reserved
  19. **
  20. ** $HISTORY:
  21. **
  22. ** 30 Dec 1995 : 001.012 :  + dynamic allocation of only one frame buffer
  23. **                          PLIP_MAXMTU now 128k
  24. **                          + a bad MTU setting in ENV: will be
  25. **                          forced to PLIP_MAXMTU instead of PLIP_DEFMTU
  26. **                          + server task acknowledge now after calling
  27. **                          readargs to avoid inconsistencies
  28. ** 03 Sep 1995 : 001.011 :  hardware addressing nicer
  29. ** 30 Aug 1995 : 001.010 :  + support for timer-timed timeout :-)
  30. **                          + minor declaration related changes
  31. ** 20 Aug 1995 : 001.009 :  support for ASM xfer routines
  32. **                          removed obsolete CIA macros (mag/jk/mm)
  33. ** 29 Jul 1995 : 001.008 :  support for arbitration delay
  34. **                          symmetrical handling
  35. ** 26 Apr 1995 : 001.007 :  _very_ nasty bug would miss packets and get
  36. **                          the driver totally irritated
  37. ** 25 Apr 1995 : 001.006 :  now compiles with ANSI and STRICT
  38. **                          fixed bug with resource allocation
  39. ** 08 Mar 1995 : 001.005 :  write req. are now handled by device.c
  40. ** 06 Mar 1995 : 001.004 :  collision delay added
  41. ** 06 Mar 1995 : 001.003 :  hardware transmission errors are no longer retried
  42. **                          because this is any upper layers job
  43. ** 04 Mar 1995 : 001.002 :  event tracking *much* more conform to SANA-2
  44. ** 18 Feb 1995 : 001.001 :  startup now a bit nicer
  45. **                          using BASEPTR
  46. ** 12 Feb 1995 : 001.000 :  reworked original
  47. */
  48.  
  49. #define DEBUG 0
  50.  
  51. /*F*/ /* includes */
  52. #ifndef CLIB_EXEC_PROTOS_H
  53. #include <clib/exec_protos.h>
  54. #include <pragmas/exec_sysbase_pragmas.h>
  55. #endif
  56. #ifndef CLIB_DOS_PROTOS_H
  57. #include <clib/dos_protos.h>
  58. #include <pragmas/dos_pragmas.h>
  59. #endif
  60. #ifndef CLIB_CIA_PROTOS_H
  61. #include <clib/cia_protos.h>
  62. #include <pragmas/cia_pragmas.h>
  63. #endif
  64. #ifndef CLIB_MISC_PROTOS_H
  65. #include <clib/misc_protos.h>
  66. #include <pragmas/misc_pragmas.h>
  67. #endif
  68. #ifndef CLIB_TIME_PROTOS_H
  69. #include <clib/timer_protos.h>
  70. #include <pragmas/timer_pragmas.h>
  71. #endif
  72. #ifndef CLIB_UTILITY_PROTOS_H
  73. #include <clib/utility_protos.h>
  74. #include <pragmas/utility_pragmas.h>
  75. #endif
  76.  
  77. #ifndef EXEC_MEMORY_H
  78. #include <exec/memory.h>
  79. #endif
  80. #ifndef EXEC_INTERRUPTS_H
  81. #include <exec/interrupts.h>
  82. #endif
  83. #ifndef EXEC_DEVICES_H
  84. #include <exec/devices.h>
  85. #endif
  86. #ifndef EXEC_IO_H
  87. #include <exec/io.h>
  88. #endif
  89.  
  90. #ifndef DEVICES_SANA2_H
  91. #include <devices/sana2.h>
  92. #endif
  93.  
  94. #ifndef HARDWARE_CIA_H
  95. #include <hardware/cia.h>
  96. #endif
  97.  
  98. #ifndef RESOURCES_MISC_H
  99. #include <resources/misc.h>
  100. #endif
  101.  
  102. #ifndef _STRING_H
  103. #include <string.h>
  104. #endif
  105.  
  106. #ifndef __MAGPLIP_H
  107. #include "magplip.h"
  108. #endif
  109. #ifndef __DEBUG_H
  110. #include "debug.h"
  111. #endif
  112. #ifndef __COMPILER_H
  113. #include "compiler.h"
  114. #endif
  115. /*E*/
  116.  
  117. /*F*/ /* defines, types and enums */
  118.  
  119.    /*
  120.    ** return codes for arbitratedwrite()
  121.    */
  122. typedef enum { AW_OK, AW_ABORTED, AW_BUFFER_ERROR, AW_ERROR } AW_RESULT;
  123.  
  124.    /* return val, cut to min or max if exceeding range */
  125. #define BOUNDS(val, min, max) ((val) <= (max) ? ((val) >= (min) ? (val) :\
  126.                                                          (min)) : (max))
  127.  
  128. /*E*/
  129. /*F*/ /* imports */
  130.    /* external functions */
  131. GLOBAL VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd);
  132. GLOBAL VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2);
  133. GLOBAL USHORT ASM CRC16(REG(a0) UBYTE *, REG(d0) SHORT);
  134. GLOBAL BOOL ASM hwsend(REG(a0) BASEPTR);
  135. GLOBAL BOOL ASM hwrecv(REG(a0) BASEPTR);
  136. GLOBAL VOID ASM interrupt(REG(a1) BASEPTR);
  137.  
  138.    /* amiga.lib provides for these symbols */
  139. GLOBAL FAR volatile struct CIA ciaa,ciab;
  140. /*E*/
  141. /*F*/ /* exports */
  142. PUBLIC VOID SAVEDS ServerTask(void);
  143. /*E*/
  144. /*F*/ /* private */
  145. PRIVATE struct PLIPBase *startup(void);
  146. PRIVATE REGARGS VOID DoEvent(BASEPTR, long event);
  147. PRIVATE VOID readargs(BASEPTR);
  148. PRIVATE BOOL init(BASEPTR);
  149. PRIVATE BOOL hwattach(BASEPTR);
  150. PRIVATE VOID hwdetach(BASEPTR);
  151. PRIVATE REGARGS BOOL goonline(BASEPTR);
  152. PRIVATE REGARGS VOID gooffline(BASEPTR);
  153. PRIVATE REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2);
  154. PRIVATE REGARGS VOID dowritereqs(BASEPTR);
  155. PRIVATE REGARGS VOID doreadreqs(BASEPTR);
  156. PRIVATE REGARGS VOID dos2reqs(BASEPTR);
  157. /*E*/
  158.  
  159. /*F*/ /* CIA access macros & functions */
  160.  
  161. #define CLEARINT        SetICR(CIAABase, CIAICRF_FLG)
  162. #define DISABLEINT      AbleICR(CIAABase, CIAICRF_FLG)
  163. #define ENABLEINT       AbleICR(CIAABase, CIAICRF_FLG | CIAICRF_SETCLR)
  164.  
  165. #define SETCIAOUTPUT    ciaa.ciaddrb = 0xFF
  166. #define SETCIAINPUT     ciaa.ciaddrb = 0x00
  167. #define PARINIT(b)      SETCIAINPUT;                                       \
  168.                         ciab.ciaddra &= ~((b)->pb_HandshakeMask[HS_LINE]); \
  169.                         ciab.ciaddra |= (b)->pb_HandshakeMask[HS_REQUEST]
  170.  
  171. #define TESTLINE(b)     (ciab.ciapra & (b)->pb_HandshakeMask[HS_LINE])
  172. #define SETREQUEST(b)   ciab.ciapra |= (b)->pb_HandshakeMask[HS_REQUEST]
  173. #define CLEARREQUEST(b) ciab.ciapra &= ~((b)->pb_HandshakeMask[HS_REQUEST])
  174.  
  175. /*E*/
  176.  
  177.    /*
  178.    ** functions to gain/release hardware, initialise communication
  179.    ** and for xmission timeout handling
  180.    */
  181. /*F*/ PRIVATE BOOL hwattach(BASEPTR)
  182. {
  183.    BOOL rc = FALSE;
  184.  
  185.    d(("entered\n"));
  186.  
  187.    if (MiscBase = OpenResource("misc.resource"))
  188.    {
  189.       if (CIAABase = OpenResource("ciaa.resource"))
  190.       {
  191.          CiaBase = CIAABase;
  192.  
  193.          d(("ciabase is %lx\n",CiaBase));
  194.  
  195.          /* obtain exclusive access to the parallel hardware */
  196.          if (!AllocMiscResource(MR_PARALLELPORT, pb->pb_DevNode.lib_Node.ln_Name))
  197.          {
  198.             pb->pb_AllocFlags |= 1;
  199.             if (!AllocMiscResource(MR_PARALLELBITS, pb->pb_DevNode.lib_Node.ln_Name))
  200.             {
  201.                pb->pb_AllocFlags |= 2;
  202.  
  203.                /* Add our interrupt to handle CIAICRB_FLG.
  204.                ** This is also cia.resource means of granting exclusive
  205.                ** access to the related registers in the CIAs.
  206.                */
  207.                pb->pb_Interrupt.is_Node.ln_Type = NT_INTERRUPT;
  208.                pb->pb_Interrupt.is_Node.ln_Pri  = 127;
  209.                pb->pb_Interrupt.is_Node.ln_Name = SERVERTASKNAME;
  210.                pb->pb_Interrupt.is_Data         = (APTR)pb;
  211.                pb->pb_Interrupt.is_Code         = (VOID (*)())&interrupt;
  212.  
  213.                /* We must Disable() bcos there could be an interrupt already
  214.                ** waiting for us. We may, however, not Able/SetICR() before
  215.                ** we have access!
  216.                */
  217.                Disable();
  218.                if (!AddICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt))
  219.                {
  220.                   DISABLEINT;                       /* this is what I meant */
  221.                   rc = TRUE;
  222.                }
  223.                Enable();
  224.  
  225.                if (rc)
  226.                {
  227.                   pb->pb_AllocFlags |= 4;
  228.                   PARINIT(pb);    /* cia to input, handshake in/out setting */
  229.                   CLEARREQUEST(pb);                /* setup handshake lines */
  230.                   CLEARINT;                         /* clear this interrupt */
  231.                   ENABLEINT;                            /* allow interrupts */
  232.                }
  233.  
  234.             }
  235.             else
  236.                d(("no parallelbits\n"));
  237.          }
  238.          else
  239.             d(("no parallelport\n"));
  240.       }
  241.       else
  242.          d(("no misc resource\n"));
  243.    }
  244.    else
  245.       d(("no misc resource\n"));
  246.  
  247.    return rc;
  248. }
  249. /*E*/
  250. /*F*/ PRIVATE VOID hwdetach(BASEPTR)
  251. {
  252.    if (pb->pb_AllocFlags & 4)
  253.    {
  254.       DISABLEINT;
  255.       CLEARINT;
  256.       RemICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt);
  257.    }
  258.  
  259.    if (pb->pb_AllocFlags & 2) FreeMiscResource(MR_PARALLELBITS);
  260.  
  261.    if (pb->pb_AllocFlags & 1) FreeMiscResource(MR_PARALLELPORT);
  262.  
  263.    pb->pb_AllocFlags = 0;
  264. }
  265. /*E*/
  266. /*F*/ PRIVATE ULONG ASM SAVEDS exceptcode(REG(d0) ULONG sigmask, REG(a1) BASEPTR)
  267. {
  268.    /*extern void KPrintF(char *,...);
  269.    KPrintF("exceptcode\n");*/
  270.  
  271.    /* remove the I/O Block from the port */
  272.    WaitIO((struct IORequest*)&pb->pb_TimeoutReq);
  273.  
  274.    /* this tells the xfer routines to cease polling */
  275.    pb->pb_TimeoutSet = 0xff;
  276.  
  277.    return sigmask;            /* re-enable the signal */
  278. }
  279. /*E*/
  280.  
  281.    /*
  282.    ** functions to go online/offline
  283.    */
  284. /*F*/ PRIVATE REGARGS VOID rejectpackets(BASEPTR)
  285. {
  286.    struct IOSana2Req *ios2;
  287.  
  288.    ObtainSemaphore(&pb->pb_WriteListSem);
  289.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_WriteList))
  290.    {
  291.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  292.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  293.       DevTermIO(pb,ios2);
  294.    }
  295.    ReleaseSemaphore(&pb->pb_WriteListSem);
  296.  
  297.    ObtainSemaphore(&pb->pb_ReadListSem);
  298.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadList))
  299.    {
  300.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  301.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  302.       DevTermIO(pb,ios2);
  303.    }
  304.    ReleaseSemaphore(&pb->pb_ReadListSem);
  305.  
  306.    ObtainSemaphore(&pb->pb_ReadOrphanListSem);
  307.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList))
  308.    {
  309.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  310.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  311.       DevTermIO(pb,ios2);
  312.    }
  313.    ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
  314. }
  315. /*E*/
  316. /*F*/ PRIVATE REGARGS BOOL goonline(BASEPTR)
  317. {
  318.    BOOL rc = FALSE;
  319.  
  320.    d(("trying to go online\n"));
  321.  
  322.    if (pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED))
  323.    {
  324.       if (!hwattach(pb))
  325.       {
  326.          d(("error going online\n"));
  327.       }
  328.       else
  329.       {
  330.          GetSysTime(&pb->pb_DevStats.LastStart);
  331.          pb->pb_Flags &= ~(PLIPF_OFFLINE | PLIPF_NOTCONFIGURED);
  332.          DoEvent(pb, S2EVENT_ONLINE);
  333.          rc = TRUE;
  334.          d(("i'm now online!\n"));
  335.       }
  336.    }
  337.  
  338.    return rc;
  339. }
  340. /*E*/
  341. /*F*/ PRIVATE REGARGS VOID gooffline(BASEPTR)
  342. {
  343.    if (!(pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED)))
  344.    {
  345.       hwdetach(pb);
  346.  
  347.       pb->pb_Flags |= PLIPF_OFFLINE;
  348.  
  349.       DoEvent(pb, S2EVENT_OFFLINE);
  350.    }
  351.    d(("ok!\n"));
  352. }
  353. /*E*/
  354.  
  355.    /*
  356.    ** SANA-2 Event management
  357.    */
  358. /*F*/ PRIVATE REGARGS VOID DoEvent(BASEPTR, long event)
  359. {
  360.    struct IOSana2Req *ior, *ior2;
  361.  
  362.    d(("event is %lx\n",event));
  363.  
  364.    ObtainSemaphore(&pb->pb_EventListSem );
  365.    
  366.    for(ior = (struct IOSana2Req *) pb->pb_EventList.lh_Head;
  367.        ior2 = (struct IOSana2Req *) ior->ios2_Req.io_Message.mn_Node.ln_Succ;
  368.        ior = ior2 )
  369.    {
  370.       if (ior->ios2_WireError & event)
  371.       {
  372.          Remove((struct Node*)ior);
  373.          DevTermIO(pb, ior);
  374.       }
  375.    }
  376.    
  377.    ReleaseSemaphore(&pb->pb_EventListSem );
  378. }
  379. /*E*/
  380.  
  381.    /*
  382.    ** writing packets
  383.    */
  384. /*F*/ PRIVATE REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2)
  385. {
  386.    BOOL having_line;
  387.    AW_RESULT rc;
  388.    struct PLIPFrame *frame = pb->pb_Frame;
  389.  
  390.    /*
  391.    ** Arbitration
  392.    ** ===========================================================
  393.    **
  394.    ** Pseudo code of the arbitration:
  395.    **
  396.    **  if LINE is high (other side is ready to receive) then
  397.    **     set REQUEST high (tell the other side we're ready to send)
  398.    **     if LINE is high (other side is still ready to receive) then
  399.    **        we have the line, do transfer
  400.    **     reset REQUEST to low (tell other side we're ready to receive)
  401.    **
  402.    **    AW_OK             if we could transmit all the data correctly
  403.    **    AW_BUFF_ERROR     if the BufferManagement callback failed
  404.    **    AW_ERROR          if we got the line, but the actual transfer
  405.    **                      failed, perhaps due to a timeout
  406.    **    AW_ABORT          if we couldn't get the line
  407.    */
  408.  
  409.    having_line = FALSE;
  410.  
  411.    if (!TESTLINE(pb))                               /* is the line free ? */
  412.    {
  413.       SETREQUEST(pb);                     /* indicate our request to send */
  414.       
  415. #if 0
  416.       I have removed again the ARBITRATIONDELAY feature, although I am not
  417.       really sure if this is a good thing. Anyway I didn't experience
  418.       any more those nasty line errors, that initially made me implementing
  419.       this. For now I've left the code here to let you play with it. Please
  420.       report any comments concerning this.
  421.  
  422.       In fact the arbitration leaves a small door for undetected, real
  423.       collisision, as the request lines are used for handshake during the
  424.       transmission process. The CLEARREQUEST after NOT getting the line
  425.       could be misinterpreted by the other side as the first handshake. Up
  426.       to now I couldn't conceive a satisfying solution for this.
  427.  
  428.       if (pb->pb_ArbitrationDelay > 0)
  429.       {
  430.          pb->pb_CollReq.tr_time.tv_secs    = 0;
  431.          pb->pb_CollReq.tr_time.tv_micro   = pb->pb_ArbitrationDelay;
  432.          pb->pb_CollReq.tr_node.io_Command = TR_ADDREQUEST;
  433.          DoIO((struct IORequest*)&pb->pb_CollReq);
  434.       }
  435. #endif
  436.  
  437.       if (!TESTLINE(pb))                      /* is the line still free ? */
  438.          having_line = TRUE;
  439.       else
  440.       {
  441.          if (!(pb->pb_Flags & PLIPF_RECEIVING))
  442.             CLEARREQUEST(pb);                         /* reset line state */
  443.          d2(("couldn't get the line-1\n"));
  444.       }
  445.    }
  446.    else d2(("couldn't get the line-2\n"));
  447.  
  448.    if (having_line)
  449.    {
  450.       struct BufferManagement *bm;
  451.  
  452.       if (!(pb->pb_Flags & PLIPF_RECEIVING))
  453.       {
  454.          d(("having line for: type %08lx, size %ld\n",ios2->ios2_PacketType,
  455.                                                       ios2->ios2_DataLength));
  456.  
  457.          frame->pf_Type = ios2->ios2_PacketType;
  458.          frame->pf_Size = ios2->ios2_DataLength + PKTFRAMESIZE_2;
  459.  
  460.          bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
  461.  
  462.          if (!(*bm->bm_CopyFromBuffer)((UBYTE*)(frame+1),
  463.                                      ios2->ios2_Data, ios2->ios2_DataLength))
  464.          {
  465.             rc = AW_BUFFER_ERROR;
  466.             CLEARREQUEST(pb);                         /* reset line state */
  467.          }
  468.          else
  469.          {
  470.             /* wait until I/O block is safe to be reused */
  471.             while(!pb->pb_TimeoutSet) Delay(1L);
  472.             pb->pb_TimeoutReq.tr_time.tv_secs = 0;
  473.             pb->pb_TimeoutReq.tr_time.tv_micro = pb->pb_Timeout;
  474.             pb->pb_TimeoutSet = 0;
  475.             SendIO((struct IORequest*)&pb->pb_TimeoutReq);
  476.             rc = hwsend(pb) ? AW_OK : AW_ERROR;
  477.             AbortIO((struct IORequest*)&pb->pb_TimeoutReq);
  478.          }
  479.       }
  480.       else
  481.       {
  482.          d4(("arbitration error!\n"));
  483.          rc = AW_ABORTED;
  484.       }
  485.    }
  486.    else
  487.       rc = AW_ABORTED;
  488.  
  489.    return rc;
  490. }
  491. /*E*/
  492. /*F*/ PRIVATE REGARGS VOID dowritereqs(BASEPTR)
  493. {
  494.    struct IOSana2Req *currentwrite, *nextwrite;
  495.    AW_RESULT code;
  496.  
  497.    ObtainSemaphore(&pb->pb_WriteListSem);
  498.  
  499.    for(currentwrite = (struct IOSana2Req *)pb->pb_WriteList.lh_Head;
  500.        nextwrite = (struct IOSana2Req *) currentwrite->ios2_Req.io_Message.mn_Node.ln_Succ;
  501.        currentwrite = nextwrite )
  502.    {
  503.       if (pb->pb_Flags & PLIPF_RECEIVING)
  504.       {
  505.          d(("incoming data!"));
  506.          break;
  507.       }
  508.  
  509.       code = arbitratedwrite(pb, currentwrite);
  510.  
  511.       if (code == AW_ABORTED)                         /* arbitration failed */
  512.       {
  513.          pb->pb_Flags |= PLIPF_COLLISION;
  514.          d(("couldn't get the line, trying again later\n"));
  515.          if ((currentwrite->ios2_Req.io_Error++) > pb->pb_Retries)
  516.          {
  517.             currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
  518.             currentwrite->ios2_WireError = S2WERR_TOO_MANY_RETIRES;
  519.             Remove((struct Node*)currentwrite);
  520.             DevTermIO(pb, currentwrite);
  521.          }
  522.          break;
  523.       }
  524.       else if (code == AW_BUFFER_ERROR)  /* BufferManagement callback error */
  525.       {
  526.          d(("buffer error\n"));
  527.          DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
  528.          currentwrite->ios2_Req.io_Error = S2ERR_SOFTWARE;
  529.          currentwrite->ios2_WireError = S2WERR_BUFF_ERROR;
  530.          Remove((struct Node*)currentwrite);
  531.          DevTermIO(pb, currentwrite);
  532.       }
  533.       else if (code == AW_ERROR)
  534.       {
  535.          /*
  536.          ** this is a real line error, upper levels (e.g. Internet TCP) have
  537.          ** to care for reliability!
  538.          */
  539.          d(("error transmitting packet\n"));
  540.          DoEvent(pb, S2EVENT_ERROR | S2EVENT_TX | S2EVENT_HARDWARE);
  541.          currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
  542.          currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
  543.          Remove((struct Node*)currentwrite);
  544.          DevTermIO(pb, currentwrite);
  545.       }
  546.       else /*if (code == AW_OK)*/                             /* well done! */
  547.       {
  548.          d(("packet transmitted successfully\n"));
  549.          pb->pb_DevStats.PacketsSent++;
  550.          dotracktype(pb, pb->pb_Frame->pf_Type, 1, 0, currentwrite->ios2_DataLength, 0, 0);
  551.          currentwrite->ios2_Req.io_Error = S2ERR_NO_ERROR;
  552.          currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
  553.          Remove((struct Node*)currentwrite);
  554.          DevTermIO(pb, currentwrite);
  555.       }
  556.    }
  557.  
  558.    ReleaseSemaphore(&pb->pb_WriteListSem);
  559. }
  560. /*E*/
  561.  
  562.    /*
  563.    ** reading packets
  564.    */
  565. /*F*/ PRIVATE REGARGS VOID doreadreqs(BASEPTR)
  566. {
  567.    LONG datasize;
  568.    struct IOSana2Req *got;
  569.    ULONG pkttyp;
  570.    struct BufferManagement *bm;
  571.    BOOL rv;
  572.    struct PLIPFrame *frame = pb->pb_Frame;
  573.  
  574.    /* wait until I/O block is safe to be reused */
  575.    while(!pb->pb_TimeoutSet) Delay(1L);
  576.    pb->pb_TimeoutReq.tr_time.tv_secs    = 0;
  577.    pb->pb_TimeoutReq.tr_time.tv_micro   = pb->pb_Timeout;
  578.    pb->pb_TimeoutSet = 0;
  579.    SendIO((struct IORequest*)&pb->pb_TimeoutReq);
  580.    rv = hwrecv(pb);
  581.    AbortIO((struct IORequest*)&pb->pb_TimeoutReq);
  582.  
  583.    if (rv)
  584.    {
  585.       pb->pb_DevStats.PacketsReceived++;
  586.  
  587.       datasize = frame->pf_Size - PKTFRAMESIZE_2;
  588.  
  589.       dotracktype(pb, pkttyp = frame->pf_Type, 0, 1, 0, datasize, 0);
  590.  
  591.       d(("packet %08lx, size %ld received\n",pkttyp,datasize));
  592.  
  593.       ObtainSemaphore(&pb->pb_ReadListSem);
  594.  
  595.          /* traverse the list of read-requests */
  596.       for(got = (struct IOSana2Req *)pb->pb_ReadList.lh_Head;
  597.           got->ios2_Req.io_Message.mn_Node.ln_Succ;
  598.           got = (struct IOSana2Req *)got->ios2_Req.io_Message.mn_Node.ln_Succ )
  599.       {
  600.             /* check if this one requests for the new packet we got */
  601.          if (got->ios2_PacketType == pkttyp )
  602.          {
  603.             Remove((struct Node*)got);
  604.  
  605.             bm = (struct BufferManagement *)got->ios2_BufferManagement;
  606.  
  607.             if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)(frame+1), datasize))
  608.             {
  609.                d(("CopyToBuffer: error\n"));
  610.                got->ios2_Req.io_Error = S2ERR_SOFTWARE;
  611.                got->ios2_WireError = S2WERR_BUFF_ERROR;
  612.                DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
  613.             }
  614.             else
  615.             {
  616.                got->ios2_Req.io_Error = got->ios2_WireError = 0;
  617.             }
  618.  
  619.             got->ios2_Req.io_Flags = 0;
  620.             memcpy(got->ios2_SrcAddr, pb->pb_SrcAddr, PLIP_ADDRFIELDSIZE);
  621.             memcpy(got->ios2_DstAddr, pb->pb_DstAddr, PLIP_ADDRFIELDSIZE);
  622.             got->ios2_DataLength = datasize;
  623.  
  624.             d(("packet received, satisfying S2Request\n"));
  625.             DevTermIO(pb, got);
  626.             got = NULL;
  627.             break;
  628.          }
  629.       }
  630.  
  631.       ReleaseSemaphore(&pb->pb_ReadListSem);
  632.    }
  633.    else
  634.    {     /* something went wrong during receipt */
  635.       DoEvent(pb, S2EVENT_HARDWARE | S2EVENT_ERROR | S2EVENT_RX);
  636.       got = NULL;
  637.       pb->pb_DevStats.BadData++;
  638.    }
  639.  
  640.       /* If no one wanted this packet explicitely, there is one chance
  641.       ** left: somebody waiting for orphaned packets. If this fails, too,
  642.       ** we will drop it.
  643.       */
  644.    if (got)
  645.    {
  646.       d(("unknown packet\n"));
  647.  
  648.       pb->pb_DevStats.UnknownTypesReceived++;
  649.       
  650.       ObtainSemaphore(&pb->pb_ReadOrphanListSem);
  651.       got = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList);
  652.       ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
  653.  
  654.       if (got)
  655.       {
  656.          bm = (struct BufferManagement *)got->ios2_BufferManagement;
  657.          if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)(frame+1), datasize))
  658.          {
  659.             got->ios2_Req.io_Error = S2ERR_SOFTWARE;
  660.             got->ios2_WireError = S2WERR_BUFF_ERROR;
  661.          }
  662.          else
  663.          {
  664.             got->ios2_Req.io_Error = got->ios2_WireError = 0;
  665.          }
  666.          
  667.          got->ios2_Req.io_Flags = 0;
  668.          memcpy(got->ios2_SrcAddr, pb->pb_SrcAddr, PLIP_ADDRFIELDSIZE);
  669.          memcpy(got->ios2_DstAddr, pb->pb_DstAddr, PLIP_ADDRFIELDSIZE);
  670.          got->ios2_DataLength = datasize;
  671.  
  672.          d(("orphan read\n"));
  673.  
  674.          DevTermIO(pb, got);
  675.       }
  676.       else
  677.       {
  678.          dotracktype(pb, pkttyp, 0, 0, 0, 0, 1);
  679.          d(("packet thrown away...\n"));
  680.       }
  681.    }
  682. }
  683. /*E*/
  684.  
  685.    /*
  686.    ** 2nd level device command dispatcher (~SANA2IOF_QUICK)
  687.    */
  688. /*F*/ PRIVATE REGARGS VOID dos2reqs(BASEPTR)
  689. {
  690.    struct IOSana2Req *ios2;
  691.  
  692.    /*
  693.    ** Every pending IO message will be GetMsg()'ed and processed. At the
  694.    ** end of the loop it will be DevTermIO()'ed back to the sender,
  695.    ** _but_only_if_ it is non-NULL. In such cases the message has been
  696.    ** put in a separate queue to be DevTermIO()'ed later (i.e. CMD_WRITEs
  697.    ** and similar stuff).
  698.    ** You find the same mimique in the 1st level dispatcher (device.c)
  699.    */
  700.    while(ios2 = (struct IOSana2Req *)GetMsg(pb->pb_ServerPort))
  701.    {
  702.       if (pb->pb_Flags & PLIPF_RECEIVING)
  703.       {
  704.          d(("incoming data!"));
  705.          break;
  706.       }
  707.  
  708.       d(("sana2req %ld from serverport\n", ios2->ios2_Req.io_Command));
  709.  
  710.       switch (ios2->ios2_Req.io_Command)
  711.       {
  712.          case S2_ONLINE:
  713.             if (!goonline(pb))
  714.             {
  715.                ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  716.                ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  717.             }
  718.          break;
  719.  
  720.          case S2_OFFLINE:
  721.             gooffline(pb);
  722.             rejectpackets(pb); /* reject all pending requests */
  723.          break;
  724.  
  725.          case S2_CONFIGINTERFACE:
  726.             if (pb->pb_Flags & PLIPF_NOTCONFIGURED)
  727.             {
  728.                memcpy(ios2->ios2_SrcAddr, pb->pb_SrcAddr, PLIP_ADDRFIELDSIZE);
  729.                memcpy(ios2->ios2_DstAddr, pb->pb_DstAddr, PLIP_ADDRFIELDSIZE);
  730.                
  731.                if (!goonline(pb))
  732.                {
  733.                   ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  734.                   ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  735.                }
  736.             }
  737.             else
  738.             {
  739.                ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  740.                ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
  741.             }
  742.          break;
  743.       }
  744.  
  745.       if (ios2) DevTermIO(pb,ios2);
  746.    }
  747. }
  748. /*E*/
  749.  
  750.    /*
  751.    ** startup,initialisation and termination functions
  752.    */
  753. /*F*/ PRIVATE struct PLIPBase *startup(void)
  754. {
  755.    struct ServerStartup *ss;
  756.    struct Process *we;
  757.    struct PLIPBase *base;
  758.    LOCALSYSBASE;
  759.  
  760.    we = (struct Process*)FindTask(NULL);
  761.  
  762.    d(("waiting for startup msg...\n"));
  763.    WaitPort(&we->pr_MsgPort);
  764.    ss = (struct ServerStartup *)GetMsg(&we->pr_MsgPort);
  765.    base = ss->ss_PLIPBase;
  766.    base->pb_Startup = ss;
  767.    d(("go startup msg at %lx, PLIPBase is %lx\n", ss, ss->ss_PLIPBase));
  768.  
  769.    /* we will keep the startup message, to inform mother if we
  770.    ** really could come up or if we failed to obtain some
  771.    ** resource.
  772.    */
  773.    return base;
  774. }
  775. /*E*/
  776. /*F*/ PRIVATE VOID readargs(BASEPTR)
  777. {
  778.    struct RDArgs *rda;
  779.    struct PLIPConfig args = { 0 };
  780.    BPTR plipvar, oldinput;
  781.  
  782.    d(("entered\n"));
  783.  
  784.    if (plipvar = Open(CONFIGFILE, MODE_OLDFILE))
  785.    {
  786.       oldinput = SelectInput(plipvar);
  787.       
  788.       rda = ReadArgs(TEMPLATE , (LONG *)&args, NULL);
  789.       
  790.       if(rda)
  791.       {
  792.          if (args.timeout)
  793.             pb->pb_Timeout =
  794.                   BOUNDS(*args.timeout, PLIP_MINTIMEOUT, PLIP_MAXTIMEOUT);
  795.  
  796.          if (args.priority)
  797.             SetTaskPri((struct Task*)pb->pb_Server,
  798.                   BOUNDS(*args.priority, PLIP_MINPRIORITY, PLIP_MAXPRIORITY));
  799.  
  800.          if (args.mtu)
  801.             pb->pb_MTU = BOUNDS(*args.mtu, PLIP_MINMTU, PLIP_MAXMTU);
  802.  
  803.          if (args.bps)
  804.             pb->pb_ReportBPS = BOUNDS(*args.bps, PLIP_MINBPS, PLIP_MAXBPS);
  805.  
  806.          if (args.retries)
  807.             pb->pb_Retries =
  808.                      BOUNDS(*args.retries, PLIP_MINRETRIES, PLIP_MAXRETRIES);
  809.  
  810.          if (args.sendcrc)
  811.             pb->pb_Flags |= PLIPF_SENDCRC;
  812.           else
  813.             pb->pb_Flags &= ~PLIPF_SENDCRC;
  814.  
  815.          if (args.collisiondelay)
  816.             pb->pb_CollisionDelay =
  817.                BOUNDS(*args.collisiondelay, PLIP_MINCOLLISIONDELAY,
  818.                                             PLIP_MAXCOLLISIONDELAY);
  819.          else
  820.             pb->pb_CollisionDelay = PLIP_DEFDELAY + (pb->pb_Unit ?
  821.                                                   PLIP_DELAYDIFF : 0);
  822.  
  823.          if (args.arbitrationdelay)
  824.             pb->pb_ArbitrationDelay =
  825.                BOUNDS(*args.collisiondelay, PLIP_MINARBITRATIONDELAY,
  826.                                             PLIP_MAXARBITRATIONDELAY);
  827.          else
  828.             pb->pb_ArbitrationDelay = PLIP_DEFARBITRATIONDELAY;
  829.  
  830.          FreeArgs(rda);
  831.       }
  832.  
  833.       Close(SelectInput(oldinput));
  834.    }
  835.  
  836.    d(("timeout %ld, pri %ld, mtu %ld, bps %ld, retries %ld, flags %08lx, delay %ld\n",
  837.       pb->pb_Timeout, (LONG)pb->pb_Server->pr_Task.tc_Node.ln_Pri, pb->pb_MTU, pb->pb_ReportBPS, pb->pb_Retries,
  838.       pb->pb_Flags, pb->pb_CollisionDelay));
  839.  
  840.    d(("left\n"));
  841.  
  842. }
  843. /*E*/
  844. /*F*/ PRIVATE BOOL init(BASEPTR)
  845. {
  846.    BOOL rc = FALSE;
  847.    ULONG sigmask;
  848.  
  849.    if ((pb->pb_IntSig = AllocSignal(-1)) != -1)
  850.    {
  851.       pb->pb_IntSigMask = 1L << pb->pb_IntSig;
  852.    
  853.       if ((pb->pb_ServerPort = CreateMsgPort()))
  854.       {
  855.          if ((pb->pb_CollPort = CreateMsgPort()))
  856.          {
  857.             if ((pb->pb_TimeoutPort = CreateMsgPort()))
  858.             {
  859.                /* save old exception setup */
  860.                pb->pb_OldExcept = SetExcept(0, 0xffffffff); /* turn'em off */
  861.                pb->pb_OldExceptCode = pb->pb_Server->pr_Task.tc_ExceptCode;
  862.                pb->pb_OldExceptData = pb->pb_Server->pr_Task.tc_ExceptData;
  863.  
  864.                /* create new exception setup */
  865.                pb->pb_Server->pr_Task.tc_ExceptCode = (APTR)&exceptcode;
  866.                pb->pb_Server->pr_Task.tc_ExceptData = (APTR)pb;
  867.                SetSignal(0, sigmask = (1 << pb->pb_TimeoutPort->mp_SigBit));
  868.                SetExcept(sigmask, sigmask);
  869.  
  870.                /* enter port address */
  871.                pb->pb_CollReq.tr_node.io_Message.mn_ReplyPort = pb->pb_CollPort;
  872.                if (!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest*)&pb->pb_CollReq, 0))
  873.                {
  874.                   TimerBase = (struct Library *)pb->pb_CollReq.tr_node.io_Device;
  875.  
  876.                   /* preset the io command, this will never change */
  877.                   pb->pb_CollReq.tr_node.io_Command = TR_ADDREQUEST;
  878.  
  879.                   /* setup the timeout stuff */
  880.                   pb->pb_TimeoutReq.tr_node.io_Flags = IOF_QUICK;
  881.                   pb->pb_TimeoutReq.tr_node.io_Message.mn_ReplyPort = pb->pb_TimeoutPort;
  882.                   pb->pb_TimeoutReq.tr_node.io_Device = pb->pb_CollReq.tr_node.io_Device;
  883.                   pb->pb_TimeoutReq.tr_node.io_Unit = pb->pb_CollReq.tr_node.io_Unit;
  884.                   pb->pb_TimeoutReq.tr_node.io_Command = TR_ADDREQUEST;
  885.                   pb->pb_TimeoutSet = 0xff;
  886.  
  887.                   readargs(pb);
  888.                   d(("allocating 0x%lx/%ld bytes frame buffer\n",
  889.                                        sizeof(struct PLIPFrame)+pb->pb_MTU,
  890.                                        sizeof(struct PLIPFrame)+pb->pb_MTU));
  891.                   if ((pb->pb_Frame = AllocVec((ULONG)sizeof(struct PLIPFrame) +
  892.                                                   pb->pb_MTU, MEMF_CLEAR|MEMF_ANY)))
  893.                   {
  894.                      rc = TRUE;
  895.                   }
  896.                   else
  897.                   {
  898.                      d(("couldn't allocate frame buffer\n"));
  899.                   }
  900.                }
  901.                else
  902.                {
  903.                   d(("couldn't open timer.device"));
  904.                }
  905.             }
  906.             else
  907.             {
  908.                d(("no port for timeout handling\n"));
  909.             }
  910.          }
  911.          else
  912.          {
  913.             d(("no port for collision handling\n"));
  914.          }
  915.       }
  916.       else
  917.       {
  918.          d(("no server port\n"));
  919.       }
  920.    }
  921.    else
  922.    {
  923.       d(("no signal\n",rc));
  924.    }
  925.  
  926.    d(("left %ld\n",rc));
  927.  
  928.    return rc;
  929. }
  930. /*E*/
  931. /*F*/ PRIVATE VOID cleanup(BASEPTR)
  932. {
  933.    struct BufferManagement *bm;
  934.  
  935.    gooffline(pb);
  936.  
  937.    while(bm = (struct BufferManagement *)RemHead((struct List *)&pb->pb_BufferManagement))
  938.       FreeVec(bm);
  939.  
  940.    if (pb->pb_Frame) FreeVec(pb->pb_Frame);
  941.  
  942.    if (pb->pb_TimeoutPort)
  943.    {
  944.       /* restore old exception setup */
  945.       SetExcept(0, 0xffffffff);    /* turn'em off */
  946.       pb->pb_Server->pr_Task.tc_ExceptCode = pb->pb_OldExceptCode;
  947.       pb->pb_Server->pr_Task.tc_ExceptData = pb->pb_OldExceptData;
  948.       SetExcept(pb->pb_OldExcept, 0xffffffff);
  949.  
  950.       if (TimerBase)
  951.       {
  952.          WaitIO((struct IORequest*)&pb->pb_TimeoutReq);
  953.          CloseDevice((struct IORequest*)&pb->pb_CollReq);
  954.       }
  955.       DeleteMsgPort(pb->pb_TimeoutPort);
  956.    }
  957.    if (pb->pb_CollPort) DeleteMsgPort(pb->pb_CollPort);
  958.  
  959.    if (pb->pb_ServerPort) DeleteMsgPort(pb->pb_ServerPort);
  960.    if (pb->pb_IntSig != -1) FreeSignal(pb->pb_IntSig);
  961.  
  962.    if (pb->pb_Flags & PLIPF_REPLYSS)
  963.    {
  964.       Forbid();
  965.       ReplyMsg((struct Message*)pb->pb_Startup);
  966.    }
  967. }
  968. /*E*/
  969.  
  970.    /*
  971.    ** entry point, mainloop
  972.    */
  973. /*F*/ PUBLIC VOID SAVEDS ServerTask(void)
  974. {
  975.    BASEPTR;
  976.  
  977.    d(("server running\n"));
  978.  
  979.    if (pb = startup())
  980.    {
  981.          /* if we fail to allocate all resources, this flag reminds cleanup()
  982.          ** to ReplyMsg() the startup message
  983.          */
  984.       pb->pb_Flags |= PLIPF_REPLYSS;
  985.  
  986.       if (init(pb))
  987.       {
  988.          ULONG recv, portsigmask, timersigmask, wmask;
  989.          BOOL running, timerqueued = FALSE;
  990.  
  991.          /* Ok, we are fine and will tell this mother personally :-) */
  992.          pb->pb_Startup->ss_Error = 0;
  993.          /* don't forget this, or we will have to keep a warm place */
  994.          /* in our coffin for the system */
  995.          pb->pb_Flags &= ~PLIPF_REPLYSS;
  996.          ReplyMsg((struct Message*)pb->pb_Startup);
  997.  
  998.          portsigmask  = 1 << pb->pb_ServerPort->mp_SigBit;
  999.          timersigmask = 1 << pb->pb_CollPort->mp_SigBit;
  1000.       
  1001.          wmask = SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C | pb->pb_IntSigMask | portsigmask | timersigmask;
  1002.  
  1003.          for(running=TRUE;running;)
  1004.          {
  1005.             d(("wmask is 0x%08lx\n", wmask));
  1006.  
  1007.             if (!(pb->pb_Flags & PLIPF_RECEIVING))
  1008.                recv = Wait(wmask);
  1009.             else
  1010.                SetSignal(0, pb->pb_IntSigMask);
  1011.  
  1012.             /*if (recv & pb->pb_IntSigMask)*/
  1013.             if (pb->pb_Flags & PLIPF_RECEIVING)
  1014.             {
  1015.                d(("received an interrupt\n"));
  1016.                doreadreqs(pb);
  1017.             }
  1018.  
  1019.             if (recv & portsigmask)
  1020.             {
  1021.                d(("SANA-II request(s)\n"));
  1022.                dos2reqs(pb);
  1023.             }
  1024.  
  1025.             if (recv & timersigmask)
  1026.             {
  1027.                /* pop message */
  1028.                AbortIO((struct IORequest*)&pb->pb_CollReq);
  1029.                WaitIO((struct IORequest*)&pb->pb_CollReq);
  1030.                timerqueued = FALSE;
  1031.                d(("timer wakeup\n"));
  1032.             }
  1033.  
  1034.                /* try now to do write requests (if any pending) */
  1035.             if (!timerqueued)
  1036.             {
  1037.                dowritereqs(pb);
  1038.  
  1039.                   /* don't let the other side wait too long! */
  1040.                if (pb->pb_Flags & PLIPF_RECEIVING)
  1041.                {
  1042.                   d(("received an interrupt\n"));
  1043.                   SetSignal(0, pb->pb_IntSigMask);
  1044.                   doreadreqs(pb);
  1045.                }
  1046.  
  1047.                /*
  1048.                ** Possible a collision has occurred, which is indicated by a
  1049.                ** special flag in PLIPBase.
  1050.                **
  1051.                ** Using timer.device we periodically will be waked up. This
  1052.                ** allows us to delay write packets in cases when we cannot get
  1053.                ** the line immediately.
  1054.                **
  1055.                ** If client and server are very close together, regarding the point
  1056.                ** of performance, the same delay time could even force multiple
  1057.                ** collisions (at least theoretical, I made no practical tests).
  1058.                ** Probably a CSMA/CD-like random-timed delay would be ideal.
  1059.                */
  1060.                if (pb->pb_Flags & PLIPF_COLLISION)
  1061.                {
  1062.                   pb->pb_Flags &= ~PLIPF_COLLISION;
  1063.                   pb->pb_CollReq.tr_time.tv_secs    = 0;
  1064.                   pb->pb_CollReq.tr_time.tv_micro   = pb->pb_CollisionDelay;
  1065.                   SendIO((struct IORequest*)&pb->pb_CollReq);
  1066.                   timerqueued = TRUE;
  1067.                }
  1068.             }
  1069.  
  1070.             if (recv & SIGBREAKF_CTRL_C)
  1071.             {
  1072.                d(("received break signal\n"));
  1073.                running = FALSE;
  1074.             }
  1075.          }
  1076.  
  1077.          if (timerqueued)
  1078.          {
  1079.                /* finnish pending timer requests */
  1080.             AbortIO((struct IORequest*)&pb->pb_CollReq);
  1081.             WaitIO((struct IORequest*)&pb->pb_CollReq);
  1082.          }
  1083.       }
  1084.       else
  1085.          d(("init() failed\n"));
  1086.  
  1087.       d(("cleaning up\n"));
  1088.       cleanup(pb);
  1089.  
  1090.             /* Exec will enable it's scheduler after we're dead. */
  1091.       Forbid();
  1092.             /* signal mother we're done */
  1093.       if (pb->pb_ServerStoppedSigMask)
  1094.          Signal(pb->pb_Task, pb->pb_ServerStoppedSigMask);
  1095.       pb->pb_Flags |= PLIPF_SERVERSTOPPED;
  1096.    }
  1097.    else
  1098.       d(("no startup packet\n"));
  1099. }
  1100. /*E*/
  1101.  
  1102.